package com.zhenai.sys.dao.utils.tree;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import com.zhenai.sys.vo.resp.SysDeptResp;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author wangrongji
 * @date 2023-09-06 19:04
 */
public class TreeNodeUtils {



    // 在树结构中通过id得到指定节点
    public static <T, S extends TreeNode<T, S>> S getTreeNodeById(T id, List<S> nodes) {
        for (S node : nodes) {
            if (node.id().equals(id)) {
                return node;
            }
            List<S> nextChildrenNodes = (List<S>) node.getChildrenNodes();
            if (CollectionUtils.isEmpty(nextChildrenNodes)) {
                continue;
            }
            S treeDataById = getTreeNodeById(id, nextChildrenNodes);
            if (!Objects.isNull(treeDataById)) {
                return treeDataById;
            }
        }
        return null;
    }


    /**
     * 根据指定节点构建一个树, 且需要包括路径上的节点
     *
     * @param allNodeList     所有节点
     * @param appointNodeList 指定节点
     * @param <T>             id
     * @param <S>             self
     * @return 树形结构对象
     */
    public static <T, S extends TreeNode<T, S>> List<S> generateTreesByAppointListV2(List<S> allNodeList, List<S> appointNodeList) {
        if (CollectionUtils.isEmpty(allNodeList) || CollectionUtils.isEmpty(appointNodeList)) {
            return new ArrayList<>();
        }

        Map<T, S> allMap = allNodeList.stream().collect(Collectors.toMap(S::id, v -> v, (v1, v2) -> v1));

        //1、根据部分节点 查出所有父级节点（含当前节点）
        List<S> data = Lists.newArrayList();
        for (S node : appointNodeList) {
            data = findParentList(allMap, node, data);
        }
        //2、根据列表构建一颗完整的树
        return generateTreesV2(data);
    }

	/**
	* 根据列表 构建一棵树
	*/
    public static <T, S extends TreeNode<T, S>> List<S> generateTreesV2(List<S> data) {
        if (CollUtil.isEmpty(data)) {
            return Lists.newArrayList();
        }
        //去重
        Collection<S> uniqueData  = data.stream().collect(Collectors.toMap(S::id, v -> v, (o1, o2) -> o1)).values();

        Map<T, List<S>> parentIdMap = uniqueData.stream().collect(Collectors.groupingBy(k -> k.parentId()));
        List<S> roots = uniqueData.stream().filter(f -> f.root()).collect(Collectors.toList());
        List<S> tree = setChildrenV2(parentIdMap, roots);
        //重排序
        return sortOrderNum(tree);
    }

    public static <T, S extends TreeNode<T, S>> List<S> setChildrenV2(Map<T, List<S>> parentIdMap, List<S> list) {
        if (CollUtil.isEmpty(list)) {
            return Lists.newArrayList();
        }
        for (S s : list) {
            //设置子级数据
            List<S> childrenList = parentIdMap.get(s.id());
            s.setChildrenNodes(setChildrenV2(parentIdMap, childrenList));
        }
        return list;
    }

    /**
     * 获取 某个节点的 所有父级列表
     *
     * @author 汪焰
     * @date 2024/9/11 16:58
     */
    public static <S extends TreeNode<T, S>, T> List<S> findParentList(Map<T, S> allMap, S node, List<S> data) {
        if (ObjectUtil.isEmpty(node)) {
            return data;
        }
        //防止data里面数据重复 ，也可以减少重复往上找
        if (data.contains(node)) {
            return data;
        }
        data.add(node);
        S parent = allMap.get(node.parentId());
        return findParentList(allMap, parent, data);
    }

	/**
	* 重排序
	*/
    public static <S extends TreeNode<T, S>, T> List<S> sortOrderNum(List<S> data) {
        if (CollUtil.isEmpty(data)) {
            return Lists.newArrayList();
        }

        Collections.sort(data, (v1, v2) -> {
            int compare = 0;
            if (ObjectUtil.isNotEmpty(v1.orderNum()) && ObjectUtil.isNotEmpty(v1.orderNum())) {
                compare = Integer.compare(v1.orderNum(), v2.orderNum());
            }
            if (ObjectUtil.isNotEmpty(v1.id()) && ObjectUtil.isNotEmpty(v1.id())
                    && v1.id() instanceof Long && v2.id() instanceof Long) {
                compare = compare != 0 ? compare : Long.compare((Long) v1.id(), (Long) v2.id());
            }
            return compare;

        });
        for (S resp : data) {
            resp.setChildrenNodes(sortOrderNum((List<S>) resp.getChildrenNodes()));
        }
        return data;
    }

}
